|
(*~\Глагол\Отделы\Поле~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**) ОТДЕЛ Читать;
(*============================================================================*
* НАЗНАЧЕНИЕ: чтение из потока *
* ПРИМЕЧАНИЯ: *
* для предварительного чтения используется промежуточная память (ПП), *
* которая заполняется заранее *
*============================================================================*)
ИСПОЛЬЗУЕТ
ОБХОД,
ОС,
Знак ИЗ "..\Иное\";
ПОСТ
(* обработка знаков *)
знУни- = 0; (* заголовок 0FFH,0FEH *)
знВин- = 1; (* по 1251 таблице *)
знДос- = 2; (* по 866 таблице *)
Размер = 4096; (* размер ПП *)
ВИД
ДЦепь = ДОСТУП К ЦЕПЬ;
ППамять = РЯД Размер ИЗ ОБХОД.Ячейка;
Поток- = ДОСТУП К ОписаниеПотока;
ОписаниеПотока = НАБОР
память:ППамять; (* ячейки ПП *)
занято:ЦЕЛ; (* ячеек занятых данными *)
выбрано:ЦЕЛ; (* уже выбранных ячеек *)
фссылка:ЦЕЛ; (* ссылка на файл в ОС *)
фпозиция:ЦЕЛ; (* позиция в файле *)
началоСтроки:КЛЮЧ; (* ВКЛ, в начале строки *)
видЗнаков+:ЦЕЛ; (* обработка знаков *)
КОН;
(******************************************************************************)
ЗАДАЧА Наполнить(поток:Поток);
(* Наполняет ПП потока данными из файла *)
УКАЗ
поток.занято:=ОС.ЧитатьФ(поток.фссылка,поток.память,Размер);
поток.выбрано:=0
КОН Наполнить;
(******************************************************************************)
ЗАДАЧА Открыть-(имяфайла-:ЦЕПЬ):Поток;
(* Открывает новый поток *)
ПЕР
поток:Поток;
фссылка:ЦЕЛ;
УКАЗ
фссылка:=ОС.ФДляЧтения(имяфайла);
ЕСЛИ фссылка = 0 ТО
ВОЗВРАТ ПУСТО
КОН;
СОЗДАТЬ(поток);
поток.фссылка:=фссылка;
поток.фпозиция:=0;
поток.началоСтроки:=ВКЛ;
поток.видЗнаков:=знВин; (* будет знУни!! *)
Наполнить(поток);
ВОЗВРАТ поток
КОН Открыть;
(******************************************************************************)
ЗАДАЧА Закрыть-(поток+:Поток);
(* Закрывает поток *)
УКАЗ
ОС.ЗакрытьФ(поток.фссылка);
поток:=ПУСТО
КОН Закрыть;
(******************************************************************************)
ЗАДАЧА Конец-(поток:Поток):КЛЮЧ;
(* Возвращает ВКЛ, если в потоке уже окончились данные *)
УКАЗ
ВОЗВРАТ поток.занято = 0
КОН Конец;
(******************************************************************************)
ЗАДАЧА Позиция-(поток:Поток):ЦЕЛ;
(* Возвращает позицию, отсчитываемую от начала файла *)
УКАЗ
ВОЗВРАТ поток.фпозиция
КОН Позиция;
(******************************************************************************)
ЗАДАЧА СменаПозиции-(поток:Поток; поз:ЦЕЛ);
(* Меняет позицию чтения на <поз>, отсчитываемую от начала файла *)
УКАЗ
ОС.СменаПозицииФ(поток.фссылка,поз);
Наполнить(поток);
поток.фпозиция:=поз
КОН СменаПозиции;
(******************************************************************************)
ЗАДАЧА Ячейки-(поток:Поток; память+:ОБХОД.Ячейки; размер:ЦЕЛ);
(* Читает в <память> определенное число ячеек.
* При невозможности чтения заполняет ячейки нулями *)
ПЕР
поз:ЦЕЛ;
УКАЗ
ОТ поз:=0 ДО размер-1 ВЫП
ЕСЛИ Конец(поток) ТО
память[поз]:=0
ИНАЧЕ
память[поз]:=поток.память[поток.выбрано];
УВЕЛИЧИТЬ(поток.выбрано);
УВЕЛИЧИТЬ(поток.фпозиция);
ЕСЛИ поток.выбрано >= поток.занято ТО
Наполнить(поток)
КОН
КОН
КОН
КОН Ячейки;
(******************************************************************************)
ЗАДАЧА БудутЯчейки(поток:Поток; память+:ОБХОД.Ячейки; размер:ЦЕЛ);
ПЕР
поз:ЦЕЛ;
УКАЗ
ОТ поз:=0 ДО размер-1 ВЫП
память[поз]:=поток.память[поток.выбрано+поз]
КОН
КОН БудутЯчейки;
(******************************************************************************)
ЗАДАЧА БудетЗнак-(поток:Поток):ЗНАК;
ПЕР
знак:ЗНАК;
уз:ЯЧЦЕЛ;
УКАЗ
ЕСЛИ Конец(поток) ТО
ВОЗВРАТ 0X
КОН;
ЕСЛИ поток.видЗнаков = знУни ТО
БудутЯчейки(поток,знак,2);
ЕСЛИ (поток.фпозиция = 0) И (знак = "#FEFF") ТО
Ячейки(поток,знак,2);
БудутЯчейки(поток,знак,2)
КОН
ИНАЧЕ
БудутЯчейки(поток,уз,1);
ЕСЛИ поток.видЗнаков = знДос ТО
знак:=Знак.ИзДос(уз)
ИНАЧЕ
знак:=Знак.ИзВин(уз)
КОН
КОН;
ВОЗВРАТ знак
КОН БудетЗнак;
(******************************************************************************)
ЗАДАЧА ЗнакЦепи-(поток:Поток):ЗНАК;
(* Считывает знак из потока *)
ПЕР
знак:ЗНАК;
уз:ЯЧЦЕЛ;
УКАЗ
ЕСЛИ поток.видЗнаков = знУни ТО
Ячейки(поток,знак,2);
ЕСЛИ (поток.фпозиция = 2) И (знак = "#FEFF") ТО
Ячейки(поток,знак,2)
КОН
ИНАЧЕ
Ячейки(поток,уз,1);
ЕСЛИ поток.видЗнаков = знДос ТО
знак:=Знак.ИзДос(уз)
ИНАЧЕ
знак:=Знак.ИзВин(уз)
КОН
КОН;
ВОЗВРАТ знак
КОН ЗнакЦепи;
(******************************************************************************)
ЗАДАЧА Строка-(поток:Поток; цепь+:ЦЕПЬ);
(* Считывает строку знаков из потока в цепочку знаков. При этом
* конец строки "#000D#000A" не записывается в конец этой цепочки *)
ПЕР
занято:ЦЕЛ;
знак:ЗНАК;
УКАЗ
занято:=0;
КОЛЬЦО
ЕСЛИ (занято >= РАЗМЕР(цепь)) ИЛИ Конец(поток) ТО
поток.началоСтроки:=ОТКЛ;
ВЫХОД
КОН;
знак:=ЗнакЦепи(поток);
ЕСЛИ знак = 0DX ТО
поток.началоСтроки:=ВКЛ;
знак:=ЗнакЦепи(поток); (* 0AX *)
ВЫХОД
АЕСЛИ знак = 0AX ТО
поток.началоСтроки:=ВКЛ;
ВЫХОД
КОН;
цепь[занято]:=знак;
УВЕЛИЧИТЬ(занято)
КОН;
ЕСЛИ занято < РАЗМЕР(цепь) ТО
цепь[занято]:=0X
КОН
КОН Строка;
(******************************************************************************)
ЗАДАЧА ПропуститьСтроку-(поток:Поток);
(* Пропускает в потоке строку знаков *)
УКАЗ
поток.началоСтроки:=ОТКЛ;
ПОКА НЕ Конец(поток) ВЫП
ЕСЛИ ЗнакЦепи(поток) = 0AX ТО
поток.началоСтроки:=ВКЛ;
ВОЗВРАТ
КОН
КОН
КОН ПропуститьСтроку;
(******************************************************************************)
ЗАДАЧА ДлинаЦепь-(поток:Поток):ДЦепь;
(* Читает длину цепочки и саму цепочку во вновь распределённую память *)
ПЕР
длина,поз:ЦЕЛ;
дцепь:ДЦепь;
УКАЗ
Ячейки(поток,длина,4);
СОЗДАТЬ(дцепь,длина+1);
ОТ поз:=0 ДО длина-1 ВЫП
дцепь[поз]:=ЗнакЦепи(поток)
КОН;
дцепь[длина]:=0X;
ВОЗВРАТ дцепь
КОН ДлинаЦепь;
(******************************************************************************)
ЗАДАЧА НачалоСтроки-(поток:Поток):КЛЮЧ;
(* Возвращает ВКЛ, если задача Строка или задача ПропуститьСтроку в прошлый раз
* прочитали конец строки "#000D#000A" *)
УКАЗ
ВОЗВРАТ поток.началоСтроки
КОН НачалоСтроки;
(******************************************************************************)
ЗАДАЧА Целое-(поток:Поток; цОтвет+:ШИРЦЕЛ; вОтвет+:ШИРВЕЩ):КЛЮЧ;
(* Считывает из потока знаковое представление числа.
* Если это представление целого числа, то возвращает ВКЛ и записывает
* значение числа в <цОтвет>, иначе возвращает ОТКЛ, а значение записывает
* в <вОтвет>.
* Следующий за числом знак остаётся в потоке *)
ПЕР
i,m,n,d,эксп:ЦЕЛ;
цифры:ЦЕПЬ[64];
ошибка:КЛЮЧ;
мант:ШИРВЕЩ;
знакМант,знакЭксп:ЦЕЛ;
знак:ЗНАК; (* будущий знак *)
(******************************************************************************)
ЗАДАЧА ЗнакЦифра(знак:ЗНАК):КЛЮЧ;
УКАЗ
ЕСЛИ ("0" <= знак) И (знак <= "9") ТО
ВОЗВРАТ ВКЛ
ИНАЧЕ
ВОЗВРАТ ОТКЛ
КОН
КОН ЗнакЦифра;
(******************************************************************************)
ЗАДАЧА ЧитатьЗнак;
(* Считывает будущий знак из потока *)
ПЕР
прошлыйЗнак:ЗНАК;
УКАЗ
прошлыйЗнак:=ЗнакЦепи(поток);
знак:=БудетЗнак(поток)
КОН ЧитатьЗнак;
(******************************************************************************)
ЗАДАЧА ДесятьВ(x:ЦЕЛ):ШИРВЕЩ;
(* 10 в степени *)
ПЕР
ответ,множитель:ШИРВЕЩ;
УКАЗ
ответ:=1;
множитель:=10;
ПОКА x > 0 ВЫП
ЕСЛИ НЕ ЧЕТ(x) ТО
ответ:=ответ*множитель
КОН;
x:=x ДЕЛИТЬ 2;
ЕСЛИ x > 0 ТО (* защита <множитель> от переполнения *)
множитель:=множитель*множитель
КОН
КОН;
ВОЗВРАТ ответ
КОН ДесятьВ;
(******************************************************************************)
ЗАДАЧА ЗнакВЦел(знак:ЗНАК; система16:КЛЮЧ):ЦЕЛ;
УКАЗ
ЕСЛИ ЗнакЦифра(знак) ТО
ВОЗВРАТ ВЦЕЛ(знак)-ВЦЕЛ("0")
АЕСЛИ система16 И ("A" <= знак) И (знак <= "F") ТО
ВОЗВРАТ ВЦЕЛ(знак)-ВЦЕЛ("A")+10
ИНАЧЕ
ошибка:=ВКЛ
КОН
КОН ЗнакВЦел;
(******************************************************************************)
УКАЗ
вОтвет:=0;
цОтвет:=0;
ошибка:=ОТКЛ;
знак:=БудетЗнак(поток);
(* пропускаем пробелы перед первой цифрой *)
ПОКА знак <= " " ВЫП
ЕСЛИ Конец(поток) ТО
ВОЗВРАТ ВКЛ (* ошибка: достигнут конец потока *)
КОН;
ЧитатьЗнак
КОН;
знакМант:=1;
ЕСЛИ знак = "-" ТО
знакМант:=-1;
ЧитатьЗнак
АЕСЛИ знак = "+" ТО
ЧитатьЗнак
АЕСЛИ НЕ ЗнакЦифра(знак) ТО
ВОЗВРАТ ВКЛ (* ошибка: не нашли числа *)
КОН;
(* читаем мантиссу *)
i:=0; m:=0; n:=0; d:=0;
КОЛЬЦО
ЕСЛИ ЗнакЦифра(знак) ИЛИ (d = 0) И ("A" <= знак) И (знак <= "F") ТО
ЕСЛИ (m > 0) ИЛИ (знак # "0") ТО (* предстоящие нули пропускаем *)
ЕСЛИ n < РАЗМЕР(цифры) ТО
цифры[n]:=знак;
УВЕЛИЧИТЬ(n)
КОН;
УВЕЛИЧИТЬ(m)
КОН;
ЧитатьЗнак;
УВЕЛИЧИТЬ(i)
АЕСЛИ знак="," ТО
ЧитатьЗнак;
ЕСЛИ d = 0 ТО (* i > 0 *)
d:=i
ИНАЧЕ
ВОЗВРАТ ВКЛ (* ошибка: неверный знак в записи числа *)
КОН
ИНАЧЕ
ВЫХОД
КОН
КОН; (* 0 <= n <= m <= i, 0 <= d <= i *)
ЕСЛИ d = 0 ТО (* целое *)
ЕСЛИ n = m ТО
i:=0;
ЕСЛИ (знак = "H") ИЛИ (знак = "X") ТО (* 16-тиричное *)
ЧитатьЗнак;
ЕСЛИ (n > 16) ИЛИ ((n = 16) И (цифры[0] > "7")) ТО
ВОЗВРАТ ВКЛ (* ошибка: слишком большое целое *)
КОН;
ПОКА i < n ВЫП
цОтвет:=цОтвет*10H + ЗнакВЦел(цифры[i],ВКЛ);
ЕСЛИ ошибка ТО
ВОЗВРАТ ВКЛ (* ошибка: неверный знак в записи числа *)
КОН;
УВЕЛИЧИТЬ(i)
КОН
ИНАЧЕ (* 10-тичное *)
ПОКА i < n ВЫП
d:=ЗнакВЦел(цифры[i],ОТКЛ);
ЕСЛИ ошибка ТО
ВОЗВРАТ ВКЛ (* ошибка: неверный знак в записи числа *)
КОН;
УВЕЛИЧИТЬ(i);
ЕСЛИ цОтвет > (МАКС(ШИРЦЕЛ)-d) ДЕЛИТЬ 10 ТО
ВОЗВРАТ ВКЛ (* ошибка: слишком большое целое *)
КОН;
цОтвет:=цОтвет*10+d
КОН
КОН
ИНАЧЕ
ВОЗВРАТ ВКЛ (* ошибка: очень большое число *)
КОН;
цОтвет:=знакМант*цОтвет;
ВОЗВРАТ ВКЛ
ИНАЧЕ (* дробная часть *)
мант:=0; эксп:=0;
ПОКА n > 0 ВЫП (* 0 <= мант < 1 *)
УМЕНЬШИТЬ(n);
мант:=(ЗнакВЦел(цифры[n],ОТКЛ)+мант)/10;
ЕСЛИ ошибка ТО
ВОЗВРАТ ВКЛ (* ошибка: неверный знак в записи числа *)
КОН
КОН;
ЕСЛИ (знак = "E") ИЛИ (знак = "D") ТО
ЧитатьЗнак;
знакЭксп:=1;
ЕСЛИ знак = "-" ТО
знакЭксп:=-1;
ЧитатьЗнак
АЕСЛИ знак = "+" ТО
ЧитатьЗнак
КОН;
ЕСЛИ ЗнакЦифра(знак) ТО
ПОВТОРЯТЬ
n:=ЗнакВЦел(знак,ОТКЛ);
ЧитатьЗнак;
ЕСЛИ эксп <= (МАКС(ШИРЦЕЛ)-n) ДЕЛИТЬ 10 ТО
эксп:=эксп*10+n
ИНАЧЕ
ВОЗВРАТ ВКЛ (* ошибка: очень большое число *)
КОН
ДО НЕ ЗнакЦифра(знак);
эксп:=знакЭксп*эксп
ИНАЧЕ
ВОЗВРАТ ВКЛ (* ошибка: неверный знак в записи числа *)
КОН
КОН;
УМЕНЬШИТЬ(эксп,i-d-m); (* сдвиг десятичной точки *)
ЕСЛИ эксп < 0 ТО
ЕСЛИ эксп <= -307 ТО
ВОЗВРАТ ВКЛ (* ошибка: очень маленькое число *)
КОН;
вОтвет:=мант/ДесятьВ(-эксп)
ИНАЧЕ
ЕСЛИ эксп > 308 ТО
ВОЗВРАТ ВКЛ (* ошибка: очень большое число *)
КОН;
вОтвет:=мант*ДесятьВ(эксп)
КОН
КОН;
вОтвет:=знакМант*вОтвет;
ВОЗВРАТ ОТКЛ
КОН Целое;
(******************************************************************************)
ЗАДАЧА ШирВещ-(поток:Поток):ШИРВЕЩ;
ПЕР
ширцел:ШИРЦЕЛ;
ширвещ:ШИРВЕЩ;
УКАЗ
ЕСЛИ Целое(поток,ширцел,ширвещ) ТО
ВОЗВРАТ ширцел
ИНАЧЕ
ВОЗВРАТ ширвещ
КОН
КОН ШирВещ;
(******************************************************************************)
ЗАДАЧА Вещ-(поток:Поток):ВЕЩ;
УКАЗ
ВОЗВРАТ УЗК(ШирВещ(поток))
КОН Вещ;
(******************************************************************************)
ЗАДАЧА ШирЦел-(поток:Поток):ШИРЦЕЛ;
ПЕР
ширцел:ШИРЦЕЛ;
ширвещ:ШИРВЕЩ;
УКАЗ
ЕСЛИ Целое(поток,ширцел,ширвещ) ТО
ВОЗВРАТ ширцел
ИНАЧЕ
ВОЗВРАТ ВШИРЦЕЛ(ширвещ)
КОН
КОН ШирЦел;
(******************************************************************************)
ЗАДАЧА Цел-(поток:Поток):ЦЕЛ;
УКАЗ
ВОЗВРАТ УЗК(ШирЦел(поток))
КОН Цел;
КОН Читать.
|
|